package com.jccfc.iMessageFactory;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.jccfc.common.MessageUtil;
import com.jccfc.iMessage.IMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import static com.jccfc.common.MessageUtil.forEachYaml;

/**
 * @Auther: qym
 * @Date: 2020/12/28 14:00
 * @Description: 获取消息发送体工厂父类
 */
public abstract class ParentMessageFactory {

    //日志打印
    private static Logger logger = LoggerFactory.getLogger(ParentMessageFactory.class);

    //apollo 所有namespace
    public static Config[] configs = null;
    //1不使用apollo时 application.yml文件+自定义配置文件 message-config.properties application配置优先
    //2使用apollo时 自定义配置文件 message-config.properties apollo配置优先
    public static Map<String, String> propMap = null;

    //编译期初始化configs
    static {
        init();
    }

    /**
     * @Auther: qym
     * @Description: 配置文件的加载 初始化配置参数
     * @Param:
     * @Return:
     * @Date: 2020/12/28 16:11
     */
    private static void init() {
        //获取类加载器 加载默认设置配置文件信息 可没有改配置文件
        ClassLoader classLoader = getClassLoader();
        //读取自定义配置文件的配置message-config.properties
        configureByMessageConfig(classLoader);
        //配置文件application读取获取apollo配置
        URL url = findURLOfDefaultConfigurationFile(classLoader);
        //读取url地址 获取所需apollo配置以及apollo config
        configureByResource(url);
    }

    /**
     * @Auther: qym
     * @Description: 获取类加载器
     * @Param:
     * @Return: 类加载器
     * @Date: 2021/1/25 11:32
     */
    public static ClassLoader getClassLoader() {
        //获取类加载器 加载默认设置配置文件信息 可没有改配置文件
        ClassLoader classLoader = ParentMessageFactory.class.getClassLoader();
        //如果classLoader为null 从系统获取类加载器
        if (classLoader == null) {
            classLoader = ClassLoader.getSystemClassLoader();
        }
        //返回类加载器
        return classLoader;
    }

    /**
     * @Auther: qym
     * @Description: 读取配置自定义配置文件配置
     * @Param: 类加载器
     * @Return:
     * @Date: 2021/1/19 10:29
     */
    private static void configureByMessageConfig(ClassLoader classLoader) {
        //获取自定义的配置文件路径
        URL url = classLoader.getResource("message-config.properties");
        //如果url为null 没有自定义的配置文件 只需要初始化propMap不为null即可
        if (url == null) {
            propMap = new HashMap<String, String>();
            return;
        }
        //读取自定义配置放入内存
        propMap = MessageUtil.praseProperties(url.getPath());
    }

    /**
     * @Auther: qym
     * @Description: 读取application配置文件获取apollo配置
     * @Param: 类加载器
     * @Return:
     * @Date: 2020/12/29 9:18
     */
    private static URL findURLOfDefaultConfigurationFile(ClassLoader classLoader) {
        //获取application配置文件的路径
        URL url = getApplicationUrl(classLoader);
        //返回配置文件路径
        return url;
    }

    /**
     * @Auther: qym
     * @Description: 获取application的配置文件路径
     * @Param: 类加载器
     * @Return:
     * @Date: 2020/12/30 10:27
     */
    private static URL getApplicationUrl(ClassLoader classLoader) {
        //寻找外层项目的application.yml文件
        URL url = classLoader.getResource("application.yml");
        if (url != null) {
            return url;
        }
        //寻找外层项目的application.yaml文件
        url = classLoader.getResource("application.yaml");
        if (url != null) {
            return url;
        }
        //寻找外层项目的application.properties文件
        url = classLoader.getResource("application.properties");
        if (url != null) {
            return url;
        }
        //application路径获取失败的话 返回的url是null
        return url;
    }

    /**
     * @Auther: qym
     * @Description: 通过url路径解析出上层项目配置参数
     * @Param: url 上层项目文件文件路径
     * @Return:
     * @Date: 2020/12/30 9:44
     */
    private static void configureByResource(URL url) {
        //校验url是否为null
        if (url == null) {
            logger.error("找不到项目的application配置文件");
            return;
        }
        //解析yaml配置文件 获取apollo配置
        if (url.getPath().endsWith("application.yaml") || url.getPath().endsWith("application.yml")) {
            //获取apollo配置
            Map map = MessageUtil.praseYaml(url);
            if (map == null || map.isEmpty()) {
                logger.error("yaml/yml配置文件无配置");
                return;
            }
            //判断是否使用了apollo 根据apollo的 app.id属性字段判断
            String appId = (String) MessageUtil.getYamlPropertie(map, "app.id");
            //如果不存在apollo配置 则将所有配置文件的配置信息放入propMap中
            if ("".equals(appId) || appId == null) {
                //更新propMap的数据 apollo配置>application配置优先级>自定义配置文件
                forEachYaml(map, new StringBuilder(), propMap);
                return;
            }
            //从配置文件获取apollo apollo.bootstrap.namespaces属性
            String namespaces = (String) MessageUtil.getYamlPropertie(map, "apollo.bootstrap.namespaces");
            //配置文件不存在属性namespaces处理
            if ("".equals(namespaces) || namespaces == null) {
                //读取默认配置
                namespaces = "application";
            }
            //对属性apollo.bootstrap.namespaces进行切分获取命名空间
            String[] nss = namespaces.split(",");
            configs = new Config[nss.length];
            //获取各个apollo命名空间的config
            for (int i = 0; i < nss.length; i++) {
                configs[i] = ConfigService.getConfig(nss[i]);
            }
            return;
        }
        //解析properties配置文件 获取apollo配置
        if (url.getPath().endsWith("application.properties")) {
            //解析properties文件
            Map<String, String> properties = MessageUtil.praseProperties(url.getPath());
            if (properties == null || properties.isEmpty()) {
                logger.error("application.properties配置文件无配置");
                return;
            }
            //获取apollo的 app.Id属性
            String appId = properties.get("app.id");
            //如果不存在apollo配置 则将所有配置文件的配置信息放入propMap中
            if ("".equals(appId) || appId == null) {
                //更新propMap的数据 apollo配置>application配置优先级>自定义配置文件
                for (Map.Entry<String, String> entry : properties.entrySet()) {
                    propMap.put(entry.getKey(), entry.getValue());
                }
                return;
            }
            //如果存在apollo的配置获取命名空间
            String namespaces = properties.get("apollo.bootstrap.namespaces");
            //配置文件不存在属性namespaces处理
            if ("".equals(namespaces) || namespaces == null) {
                //读取默认配置
                namespaces = "application";
            }
            //对属性apollo.bootstrap.namespaces进行切分获取命名空间
            String[] nss = namespaces.split(",");
            configs = new Config[nss.length];
            //获取各个apollo config
            for (int i = 0; i < nss.length; i++) {
                configs[i] = ConfigService.getConfig(nss[i]);
            }
        }
    }

    /**
     * @Auther: qym
     * @Description: 获取配置文件数据 配置文件读取的优先级 apollo配置>applicaiton.yaml>message-config.properties
     * @Param: 需要查询的属性
     * @Return: 属性值
     * @Date: 2021/1/19 10:04
     */
    public static String getPropertie(String key) {
        String value = null;
        if (configs != null) {
            value = MessageUtil.getApolloConfigProperties(configs, key);
            if (value == null && propMap.size() != 0) {
                value = MessageUtil.getMessageConfigProperties(propMap, key);
            }
        } else if (propMap.size() != 0) {
            //没有使用apollo则在配置文件中寻找
            value = MessageUtil.getMessageConfigProperties(propMap, key);
        }
        return value;
    }

    /**
     * @Auther: qym
     * @Description: 获取消息发送实例
     * @Param:
     * @Return:
     * @Date: 2021/2/1 9:32
     */
    public IMessage getMessage() {
        return getAbstractMessage();
    }

    //抽象方法具体的获取消息发送的实例对象
    public abstract IMessage getAbstractMessage();

}
